/*
 * Created by SharpDevelop.
 * User: MyWife
 * Date: 11/1/2010
 * Time: 2:28 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections;
using System.Threading;
using System.Windows.Forms;

namespace popLib.ExtensionClass
{
	/// <summary>
	/// Description of SocketServer.
	/// </summary>
	public class SocketServer
	{
		
		public int Port;
		public Hashtable clients = new Hashtable();
		
		public event ClientHandler.ConnectionStatusChanged ConnectionStatusChangedEvent;
		public event ClientHandler.ReceiveMessage ReceiveMessageEvent;
        public bool WriteLog = true;
        TcpListener tcpListener;
				
		public SocketServer(int port)
		{
			this.Port = port;
			
		}
		Thread thread;
		public void Start(){
			thread = new Thread(StartServer);
			thread.IsBackground = true;
			thread.Start();
		}
		
		public void Stop(){
            tcpListener.Server.Close();
            tcpListener.Stop();            
            thread.Abort();            
		}
		
		private void StartServer(){
			try{
				tcpListener = new TcpListener( IPAddress.Any , Port);
				tcpListener.Start();
				while(true){
	    			Socket socket = tcpListener.AcceptSocket();
	    			if(socket.Connected){
	    				AddClient(socket);
	    			}
				}
			}catch(Exception ex){
                if (WriteLog) FileLib.writeLog(FileLib.getFullPath(DateTime.Now.ToString("yyyyMMdd HHmm") + ".txt"), ex, "PopLib.SocketServer.StartServer");
			}
		}
		
		private void AddClient( Socket socket ){
			try{
				ClientHandler client = new ClientHandler(socket);
				client.ConnectionStatusChangedEvent += Socket_StatusChanged;
				client.ReceiveMessageEvent += Socket_ReceiveMessage;			
				clients.Add( client.Name, client );
                client.WriteLog = this.WriteLog;
				
				if(ConnectionStatusChangedEvent != null)
					ConnectionStatusChangedEvent(client,true);
				
			}catch(Exception ex){
                if (WriteLog) FileLib.writeLog(FileLib.getFullPath(DateTime.Now.ToString("yyyyMMdd HHmm") + ".txt"), ex, "PopLib.SocketServer.AddClient");
			}
		}
		
		private void Socket_StatusChanged(ClientHandler client, bool isConnected){
			try{
				if(ConnectionStatusChangedEvent != null)
					ConnectionStatusChangedEvent(client,isConnected);
				
				if( !isConnected && clients.ContainsKey(client.Name) ){
					clients.Remove( client.Name );
				}
			}catch(Exception ex){
                if (WriteLog) FileLib.writeLog(FileLib.getFullPath(DateTime.Now.ToString("yyyyMMdd HHmm") + ".txt"), ex, "PopLib.SocketServer.Socket_StatusChanged");
			}
		}
		
		private void Socket_ReceiveMessage(ClientHandler client, string message){
			try{
				if(ReceiveMessageEvent != null && client != null && message != null)
					ReceiveMessageEvent(client, message);
			}catch(Exception ex){
                if (WriteLog) FileLib.writeLog(FileLib.getFullPath(DateTime.Now.ToString("yyyyMMdd HHmm") + ".txt"), ex, "PopLib.SocketServer.Socket_ReceiveMessage");
			}
		}
		
		public void SendMessage(string name, string message){
            if (clients.ContainsKey(name))
            {
                ((ClientHandler)clients[name]).SendMessage(message);
			}
		}
		
		public void SendMessageBroadcast(string message){
			foreach( ClientHandler client in clients.Values ){
				client.SendMessage(message);
			}
		}
			
	}
	
	#region class ClientHandler
	public class ClientHandler{
		public string IP;
		public string Name;
		public string Status;
		public Socket Socket;

        public bool WriteLog = true;
		
		StreamWriter streamWriter;
		StreamReader streamReader;
		
		public delegate void ConnectionStatusChanged(ClientHandler client , bool isConnected);
		public event ConnectionStatusChanged ConnectionStatusChangedEvent;
		
		public delegate void ReceiveMessage(ClientHandler client, string message);
		public event ReceiveMessage ReceiveMessageEvent;
		
		public ClientHandler(Socket socket){
			try{
				this.IP     = socket.RemoteEndPoint.ToString().Split(':')[0];
				this.Name   = socket.RemoteEndPoint.ToString();
				this.Socket = socket;

				NetworkStream networkStream = new NetworkStream(socket);
	        	streamWriter = new StreamWriter(networkStream);
				streamReader = new StreamReader(networkStream);
								
				Thread current 		 = new Thread(processClient);
				current.IsBackground = true;
				current.Start();
			}catch(Exception ex){
                if (WriteLog) FileLib.writeLog(FileLib.getFullPath(DateTime.Now.ToString("yyyyMMdd HHmm") + ".txt"), ex, "PopLib.ClientHandler");
			}
		}
		
		private void processClient(object obj){
			try{
				while(true){
					string message = streamReader.ReadLine();
					
					if(ReceiveMessageEvent != null)
						ReceiveMessageEvent( this, message );
				}				
			}catch(Exception ex){
                if (WriteLog) FileLib.writeLog(FileLib.getFullPath(DateTime.Now.ToString("yyyyMMdd HHmm") + ".txt"), ex, "PopLib.ClientHandler.processClient");
				
				if( ConnectionStatusChangedEvent != null )
					ConnectionStatusChangedEvent(this, false);
			}
			finally{ 
				Socket.Close();
			}
			
		}
		
		public void SendMessage(string message){
			try{
				streamWriter.WriteLine(message);
				streamWriter.Flush();
			}catch(Exception ex){
                if (WriteLog) FileLib.writeLog(FileLib.getFullPath(DateTime.Now.ToString("yyyyMMdd HHmm") + ".txt"), ex, "PopLib.SocketClient.SendCommand");
			}
		}
	}
	#endregion
}
